package com.filetransfer.utils;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
@Slf4j
public class RetryExecutor<T> {
    private final int maxRetries;
    private final long retryInterval;
    private final ScheduledExecutorService executor;
    public RetryExecutor(int maxRetries, long retryInterval, int threadPoolSize) {
        this.maxRetries = maxRetries;
        this.retryInterval = retryInterval;
        this.executor = Executors.newScheduledThreadPool(threadPoolSize);
    }
    /**
     * 提交需要重试的任务
     *
     * @param task     需要执行的任务，返回值为任务结果
     * @param callback 成功或失败后的回调
     */
    public void submit(Supplier<T> task, Consumer<RetryResult<T>> callback) {
        submit(task, callback, 0);
    }
    private void submit(Supplier<T> task, Consumer<RetryResult<T>> callback, int attempt) {
        executor.submit(() -> {
            try {
                T result = task.get(); // 执行任务
                callback.accept(new RetryResult<>(true, result, null, attempt)); // 成功
            } catch (Exception e) {
                if (attempt < maxRetries) {
                    log.error("error", e);
                    log.error("Attempt " + (attempt + 1) + " failed. Retrying in " + retryInterval + "ms.");
                    executor.schedule(() -> submit(task, callback, attempt + 1), retryInterval, TimeUnit.MILLISECONDS);
                } else {
                    callback.accept(new RetryResult<>(false, null, e, attempt)); // 最终失败
                }
            }
        });
    }
    /**
     * 停止调度器
     */
    public void shutdown() {
        executor.shutdown();
    }
    /**
     * 结果封装
     */
    public static class RetryResult<T> {
        private final boolean success;
        private final T result;
        private final Exception exception;
        private final int attempts;
        public RetryResult(boolean success, T result, Exception exception, int attempts) {
            this.success = success;
            this.result = result;
            this.exception = exception;
            this.attempts = attempts;
        }
        public boolean isSuccess() {
            return success;
        }
        public T getResult() {
            return result;
        }
        public Exception getException() {
            return exception;
        }
        public int getAttempts() {
            return attempts;
        }
    }
}
